use indexmap::IndexMap;
use crate::dynf::ast;
#[derive(Debug, Clone)]
pub struct Symbol {
    pub name: String
}

impl Symbol {
    fn new(name:&str) -> Symbol {
        Symbol {
            name: name.to_owned()
        }
    }
}

#[derive(Clone, Copy, PartialEq)]
pub enum SymbolTableType {
    Module,
    Function
}

#[derive(Clone)]
pub struct SymbolTable {
    pub name: String,
    pub symbols: IndexMap<String, Symbol>,
    pub sub_tables: Vec<SymbolTable>
}

impl SymbolTable {
    pub fn new(name:String,typ:SymbolTableType,line_number:usize) -> Self {
        SymbolTable {
            name,
            symbols:Default::default(),
            sub_tables:vec![]
        }
    }
    pub fn lookup(&self, name: &str) -> Option<&Symbol> {
        self.symbols.get(name)
    }
}

#[derive(Default)]
struct SymbolTableBuilder {
    tables: Vec<SymbolTable>,
}

impl SymbolTableBuilder {

    fn prepare(&mut self) {
        self.enter_scope("top", SymbolTableType::Module,0);
    }

    fn enter_scope(&mut self,name:&str,typ:SymbolTableType,line_number:usize) {
        let table = SymbolTable::new(name.to_owned(), typ, line_number);
        self.tables.push(table);
    }

    fn leave_scope(&mut self) {
        let table = self.tables.pop().unwrap();
        self.tables.last_mut().unwrap().sub_tables.push(table);
    }

    fn finish(&mut self) -> Result<SymbolTable,String> {
        assert_eq!(self.tables.len(), 1);
        let mut symbol_table = self.tables.pop().unwrap();
        Ok(symbol_table)
    }

    fn scan_program(&mut self, program: &ast::Program) {

    }

    fn scan_statement(&mut self, statement: &ast::Statement) {
        //match statement {
        //    ast::Statement::Let {sym_name,value} => {
        //
        //    }
        //}
    }

    fn register_name(&mut self,name:&str) -> Option<String> {
        let table = self.tables.last_mut().unwrap();
        let containing = table.symbols.contains_key(name);
        if !containing {
            let symbol = Symbol::new(name);
            table.symbols.insert(name.to_owned(), symbol);
        }
        None
    }
}